package cn.modoumama.utils;

import cn.modoumama.dto.GDAOBeanDetailInfoDto;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.VelocityException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import java.io.*;
import java.util.*;
import java.util.Map.Entry;

public class VelocityUtil {

    private static final String FILE_ENCODE = "UTF-8";

    public static String generateSource(String templateFile,
                                        Map<String, Object> paramMap) throws VelocityException {

        try {
            VelocityContext context = new VelocityContext();
            Set<Entry<String, Object>> entrySet = paramMap.entrySet();
            for (Entry<String, Object> entry : entrySet) {
                context.put(entry.getKey(), entry.getValue());
            }


            StringWriter sw = new StringWriter();

            VelocityEngine engine = getVelocityEngine();

            Template template = engine.getTemplate(templateFile, FILE_ENCODE);

            template.merge(context, sw);

            return sw.toString();

        } catch (ResourceNotFoundException e) {
            e.printStackTrace();
            throw new VelocityException("ResourceNotFoundException");
        } catch (ParseErrorException e) {
            e.printStackTrace();
            throw new VelocityException("ParseErrorException");
        } catch (MethodInvocationException e) {
            e.printStackTrace();
            throw new VelocityException("MethodInvocationException");
        } catch (Exception e) {
            e.printStackTrace();
            throw new VelocityException("Exception");
        }

    }

    public static String generateSourceWithCustomSource(String templateFile,
                                                        Map<String, Object> paramMap, String[] customSource, String packageName, String fileName, String outputPath) throws VelocityException {
        List<String> sourceList = null;
        if (customSource != null) {

            if (paramMap != null && paramMap.size() > 0) {
                //XML
                sourceList = getCustomSourceFromXMLFile(packageName, fileName, outputPath, customSource, paramMap);
            } else {
                //java
                sourceList = getCustomSourceFromJavaFile(packageName, fileName, outputPath, customSource);
            }
        }

        paramMap.put("customSourceList", sourceList);
        paramMap.put("gdaoToolsUtil", new GDAOToolsUtil());


        return generateSource(templateFile, paramMap);

    }


    public static List<String> getCustomSourceFromJavaFile(String packageName, String className, String sourcePath, String[] customSource) {

        try {
            String folderNames[] = packageName.split("\\.");
//			for (int i = 0; i < folderNames.length; i++) {
//				sourcePath += "/" + folderNames[i];
//			}

            StringBuffer sb = new StringBuffer(sourcePath);
            for (int i = 0; i < folderNames.length; i++) {
                sb.append(folderNames[i]);
            }
            sourcePath = sb.toString();

            File file = new File(sourcePath + "/" + className + ".java");
            if (file.exists()) {
                return getCustomSource(file, customSource);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static List<String> getCustomSourceFromXMLFile(String packageName, String xmlFileName, String sourcePath,
                                                          String[] customSource, Map<String, Object> paramMap) {

        //applicationContext-user-dao.xml
        if (xmlFileName.endsWith("-dao")) {
            List<GDAOBeanDetailInfoDto> beanDetailInfoDtos = getDAOInfoFromXMLFile(xmlFileName, sourcePath);
            paramMap.put("beanDetailInfoList", beanDetailInfoDtos);
        } else if (xmlFileName.startsWith("sqlMapConfig-")) {
            //sqlMapConfig-user.xml
            List<String> sqlMapConfigInfoList = getSqlMapConfigInfoFromXMLFile(xmlFileName, sourcePath);
            paramMap.put("sqlMapConfigInfoList", sqlMapConfigInfoList);

        }
        try {
            File file = new File(sourcePath + "/" + xmlFileName + ".xml");
            if (file.exists()) {
                return getCustomSource(file, customSource);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void printToFile(String packageName, String className,
                                   String strData, String outputPath, String suffix) {
        try {
            StringBuffer sb = new StringBuffer(outputPath);

            String folderNames[] = packageName.split("\\.");

            if (folderNames.length == 0) {
                sb.append("/");
            } else {
                for (int i = 0; i < folderNames.length; i++) {
                    sb.append("/" + folderNames[i]);
                }
            }
            File file = new File(sb.toString());
            if (!file.exists()) {
                file.mkdirs();
            } else {
                file = new File(sb.toString() + "/" + className + "." + suffix);
                if (file.exists()) {
                    file.delete();
                }
            }
            PrintWriter printWriter = new PrintWriter(
                    new OutputStreamWriter(new FileOutputStream(sb.toString()
                            + "/" + className + "." + suffix), FILE_ENCODE));
            printWriter.write(strData);
            printWriter.flush();
            printWriter.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static VelocityEngine getVelocityEngine() throws Exception {
        Properties properties = new Properties();
        // 可选值："class"--从classpath中读取，"file"--从文件系统中读取
        properties.setProperty("resource.loader", "file");
        // 如果从文件系统中读取模板，那么属性值为org.apache.velocity.runtime.resource.loader.FileResourceLoader
        properties
                .setProperty("jar.resource.loader.class",
                        "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
        // properties.setProperty("jar.resource.loader.path", "jar:file:/" +
        // DAOTool.getLibFilePath() + ToolsConst.SEPARATOR +
        // ToolsConst.DAOTOOLS_JAR_NAME);
        properties.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS,
                "org.apache.velocity.runtime.log.NullLogSystem");

        VelocityEngine engine = new VelocityEngine();

        engine.init(properties);
        return engine;

    }


    private static List<String> getCustomSource(File file, String[] customSource) {
        List<String> sourceList = new ArrayList<String>();

        if (file.getName().toLowerCase().endsWith(".java")) {
            List<String> importStrList = getJavaImportPart(file);
            StringBuffer source = new StringBuffer();
            for (String packageStr : importStrList) {
                source.append(packageStr + GDAOToolsConst.PRINT_LINE);
            }
            sourceList.add(source.toString());
        }

        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));

            String lineData = bufferedReader.readLine();
            for (int i = 0; i < customSource.length; i = i + 2) {

                while (lineData != null) {
                    if (lineData.trim().contains(customSource[i])) {
                        StringBuffer source = new StringBuffer();
                        lineData = bufferedReader.readLine();
                        while (lineData != null && !lineData.trim().contains(customSource[i + 1])) {
                            if (source.toString().length() > 0) {
                                source.append(GDAOToolsConst.PRINT_LINE);
                            }
                            source.append(lineData);
                            lineData = bufferedReader.readLine();
                        }
                        sourceList.add(source.toString());
                        break;
                    }
                    lineData = bufferedReader.readLine();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sourceList;
    }


    private static List<String> getJavaImportPart(File file) {
        List<String> sourceList = new ArrayList<String>();
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));

            String lineData = bufferedReader.readLine();
            while (lineData != null) {
                if (lineData.startsWith("import ")) {
                    sourceList.add(lineData);
                }
                if (lineData.startsWith("public ")) {
                    break;
                }

                lineData = bufferedReader.readLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sourceList;
    }


    public static List<GDAOBeanDetailInfoDto> getDAOInfoFromXMLFile(String xmlFileName, String sourcePath) {

        List<GDAOBeanDetailInfoDto> beanDetailInfoDtoList = new ArrayList<GDAOBeanDetailInfoDto>();
        BufferedReader bufferedReader = null;
        try {
            File file = new File(sourcePath + "/" + xmlFileName + ".xml");
            if (file.exists()) {
                StringBuffer sourceInfo = new StringBuffer();
                bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
                String lineData = bufferedReader.readLine();
                while (lineData != null) {
                    sourceInfo.append(lineData + GDAOToolsConst.PRINT_LINE);
                    lineData = bufferedReader.readLine();
                }

                Document document = XmlUtil.createDocument(sourceInfo.toString().getBytes());
                Element root = XmlUtil.getElementByTagName(document, "beans");
                List<Node> beanList = XmlUtil.getChildElementsByTagName(root, "bean");

                for (Node node : beanList) {
                    GDAOBeanDetailInfoDto detailInfoDto = new GDAOBeanDetailInfoDto();
                    detailInfoDto.setId(XmlUtil.getAttrValuesByName((Element) node, "id"));
                    detailInfoDto.setClassName(XmlUtil.getAttrValuesByName((Element) node, "class"));

                    List<Node> propertyList = XmlUtil.getChildElementsByTagName((Element) node, "property");

                    Element sqlMapClientElement = XmlUtil.getChildElementByTagName((Element) propertyList.get(0), "ref");
                    //Element dataSourceElement = XmlUtil.getChildElementByTagName((Element)propertyList.get(1), "ref");

                    detailInfoDto.setSqlMapClient(XmlUtil.getAttrValuesByName(sqlMapClientElement, "bean"));
                    //detailInfoDto.setDataSource(XmlUtil.getAttrValuesByName((Element)dataSourceElement, "bean"));

                    beanDetailInfoDtoList.add(detailInfoDto);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return beanDetailInfoDtoList;
    }


    public static List<String> getSqlMapConfigInfoFromXMLFile(String xmlFileName, String sourcePath) {

        List<String> sqlMapConfigInfoList = new ArrayList<String>();
        BufferedReader bufferedReader = null;
        try {
            File file = new File(sourcePath + "/" + xmlFileName + ".xml");
            if (file.exists()) {
                StringBuffer sourceInfo = new StringBuffer();
                bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
                String lineData = bufferedReader.readLine();
                while (lineData != null) {
                    sourceInfo.append(lineData + GDAOToolsConst.PRINT_LINE);
                    lineData = bufferedReader.readLine();
                }

                Document document = XmlUtil.createDocument(sourceInfo.toString().getBytes());
                Element root = XmlUtil.getElementByTagName(document, "sqlMapConfig");
                List<Node> beanList = XmlUtil.getChildElementsByTagName(root, "sqlMap");

                for (Node node : beanList) {
                    String resource = XmlUtil.getAttrValuesByName((Element) node, "resource");
                    sqlMapConfigInfoList.add(resource);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sqlMapConfigInfoList;
    }
}
